﻿<?php
/*===================================================================
# Program: MCPHP - Web Application Framework
# HomePage: http://www.ptcms.com
# Author: pakey < pakey@qq.com >
# AuthorBlog: http://www.pakey.net
# FileName: tree.class.php
# LastModify: 2012-06-20 21:43:05
# Desc: 无限极分类树形结构
====================================================================*/
 
class Tree {
	//生成树型结构所需要的2维数组
	public $arr = array();
	 
	//当前结构数组信息
	public $pid; //当前栏目父类id
	public $cid; //当前栏目id
	public $name; //当前栏目名称
	 
	 
	//生成树型结构所需修饰符号，可以换成图片
	public $icon = array('┃ ','┣━','┗━'); //栏目分隔符
	public $nbsp = '　'; //分隔符 上级栏目与本级栏目之间
 
 
	/**
	* 构造函数，初始化类
	* @param array 2维数组，例如：
	* array(
	* 1 => array('cid'=>'1','parentid'=>0,'name'=>'一级栏目一'),
	* 2 => array('cid'=>'2','parentid'=>0,'name'=>'一级栏目二'),
	* 3 => array('cid'=>'3','parentid'=>1,'name'=>'二级栏目一'),
	* 4 => array('cid'=>'4','parentid'=>1,'name'=>'二级栏目二'),
	* 5 => array('cid'=>'5','parentid'=>2,'name'=>'二级栏目三'),
	* 6 => array('cid'=>'6','parentid'=>3,'name'=>'三级栏目一'),
	* 7 => array('cid'=>'7','parentid'=>3,'name'=>'三级栏目二')
	* )
	*/
	public function init ($arr = array(), $name = '根栏目') {
		$this->arr = $arr;
		$this->ret = '';
		$this->pid = isset($this->pid) ? $this->pid : 'parentid';
		$this->cid = isset($this->cid) ? $this->cid : 'cid';
		$this->name = isset($this->name) ? $this->name : 'name';
		//对数组数据修正-》增加根栏目
		array_unshift($this->arr, array($this->cid => 0,$this->name => $name,$this->pid => '-1'));
		return is_array($arr);
	}
	 
	/**
	* 得到父级栏目的数组
	* @param int $myid 当前栏目id
	* @return array 父级栏目数组
	*/
	public function getParent ($myid) {
		$newArr = array();
		if (! isset($this->arr[$myid]))
			return false;
		// 当前栏目的父id
		$pid = $this->arr[$myid][$this->pid];
		if (is_array($this->arr)) {
			foreach ($this->arr as $id => $v) {
				if ($v[$this->cid] == $pid)
				$newArr[] = $v;
			}
		}
		return $newArr;
	}
	 
	/**
	* 得到下级栏目的信息数组
	* @param int $myid 当前栏目id
	* @return array 子级栏目数组
	*/
	public function getChild ($myid) {
		$v = $newArr = array();
		if (is_array($this->arr)) {
			foreach ($this->arr as $id => $v) {
				if ($v[$this->pid] == $myid)
					$newArr[] = $v;
			}
		}
		return $newArr ? $newArr : false;
	}
	 
	/**
	* 获取下级分类id集合数组
	* @param int $myid 当前栏目id
	* @param boolen $includeself 是否包含当前栏目id
	* @return array 子级栏目id数组
	*/
	public function getChildId ($myid, $includeself = true) {
		// 判断是否包含当前栏目id
		if ($includeself)
			$newArr[] = $myid;
		else
			$newArr = array();
		// 获取下级栏目id集合
		if (is_array($this->arr)) {
			foreach ($this->arr as $id => $v) {
				if ($v[$this->pid] == $myid)
					$newArr[] = $v[$this->cid];
			}
		}
		return $newArr ? $newArr : false;
	}
	 
	/**
	* 获取当前栏目的位置数组
	* @param int $myid 当前栏目id
	* @param array $newArr 返回数组
	* 用法：
	* $position=array();
	* $tree->getPosition(10,$position);
	* p($position);
	*/
	public function getPosition ($myid, &$newArr) {
		$a = array();
		// 数据合法性验证
		if (! isset($this->arr[$myid]))
			return false;
		 
		$newArr[] = $this->arr[$myid];
		$pid = $this->arr[$myid][$this->pid];
		 
		// 递归获取上级数据
		if (isset($this->arr[$pid]))
			$this->getPosition($pid, $newArr);
		 
		if (is_array($newArr)) {
			krsort($newArr);
			foreach ($newArr as $v) {
				$a[$v['id']] = $v;
			}
		}
		return $a;
	}
	 
	/**
	* 获取某个栏目下栏目数组列表
	* @param int $sid 父级栏目id
	* @param int $level 下级栏目级别 1为一层下级栏目
	* @param string $fieldname 数组下级栏目下标名
	* @param int $nowlevel 当前栏目级别
	*/
	public function getList ($sid, $level = 1, $fieldname = 'child', $nowlevel = 0) {
		$newArray = $this->getChild($sid);
		if (is_array($newArray)) {
			++ $nowlevel;
			foreach ($newArray as $id => $value) {
				$tmp = $this->getChild($value[$this->cid]);
				if ($nowlevel > $level)
					$newArray[$id][$fieldname] = $tmp;
				else {
					foreach ($tmp as $k => $v) {
						$tmp[$k][$fieldname] = $this->getList($v[$this->cid], $level, $fieldname, $nowlevel);
					}
					$newArray[$id][$fieldname] = $tmp;
				}
			}
		}
		return $newArray;
	}
	 
	/**
	* 得到树形结构
	* @param int $sid 初始栏目id (-1 为从根目录开始)
	* @param string $treeStr 生成的结构形式
	* 支持参数列表：
	* {cid} 当前条目cid 对应于传入数组的下标
	* {name} 当前条目name 对应于传入数组的下标
	* {url} 当前条目url 对应于传入数组的下标
	* {spacer} 分隔符位置
	* {selected=***} 选中样式
	* 例如
	* <option value="{cid}" {selected}>{spacer}{name}</option>
	* @param string $selectStr selected的具体样式 selected="selected"
	* @param int $myid 当前所在栏目id
	* @param string $adds 前置分隔符
	* @return string
	*/
	public function getTree ($sid, $treeStr, $selectStr, $myid = 0, $adds = '') {
		$number = 1;
		$child = $this->getChild($sid);
	 
		if (is_array($child)) {
			$total = count($child);
			// echo '<hr>';
			// print_r($child);
			foreach ($child as $id => $value) {
				
				$key = $prekey = ''; //分隔符 前置分隔符
				if ($number == $total) {
					$key .= $this->icon[2];
				} else {
					$key .= $this->icon[1];
					$prekey = $adds ? $this->icon[0] : '';
				}
				$spacer = $adds ? $adds . $key : '';
				// 判断是否选中状态
				if ($value[$this->cid] == $myid)
					$nstr = str_replace('{selected}', $selectStr, $treeStr);
				else
					$nstr = str_replace('{selected}', '', $treeStr);
				// 替换分隔符
				$nstr = str_replace('{spacer}', $spacer, $nstr);
				// 替换数组数据
				foreach ($value as $k => $v) {
					$nstr = str_replace('{' . $k . '}', $v, $nstr);
				}
				$ret .= $nstr;
				// var_dump( $ret);
				$ret .= $this->getTree($value[$this->cid], $treeStr, $selectStr, $myid, $adds . $prekey . $this->nbsp);
				$number ++;
			}
		}
		return $ret;
	}
	 
	/**
	* 得到树形结构数组
	* @param string $fieldname
	* @return array
	*/
	function getTreeArr ($fieldname = 'child') {
		$tree = array(); //格式化的树
		$tmpMap = array(); //临时扁平数据
		 
		 
		foreach ($this->arr as $item) {
			$tmpMap[$item[$this->cid]] = $item;
		}
		foreach ($this->arr as $item) {
			if (isset($tmpMap[$item[$this->pid]])) {
				$tmpMap[$item[$this->pid]][$fieldname][] = &$tmpMap[$item[$this->cid]];
			} else {
				$tree[] = &$tmpMap[$item[$this->cid]];
			}
		}
		unset($tmpMap);
		return $tree;
	}
}

?>
	